#include "fm1208.h"
#include "../utils/fm1208-utils.h"

#include <string.h>

#include <nfc/nfc.h>
#include <err.h>

static CMD  cmd;
static bool debug = false;

static uint8_t abtTx[MAX_FRAME_LEN];

static uint8_t abtRx[MAX_FRAME_LEN];
static size_t szRx = sizeof(abtRx);

void setDebug(bool v)
{
    debug = v;
}

bool
parseTLV(const uint8_t *pbtData, const size_t szBytes ,TLV *tlv)
{
    if (szBytes < 2 || pbtData[1]+2 != pbtData)
        return false;
    tlv->tag    = pbtData[0];
    tlv->length = pbtData[1];
    memcpy( tlv->value, pbtData+2, tlv->length );

    return true;
}

static void
print_hex (const uint8_t *pbtData, const size_t szBytes)
{
  size_t  szPos;

  for (szPos = 0; szPos < szBytes; szPos++) {
    printf ("%02x ", pbtData[szPos]);
  }
  printf ("\n");
}
   
bool transmit_bytes (nfc_device *pnd, uint8_t cmdType, const CMD *cmd, CMD_Response *res)
{
    size_t szTx = 0;

    if (cmdType & CMD_BASE)
    {
        memcpy(abtTx+szTx, cmd,CMD_BASE_LENTH);
        szTx+=CMD_BASE_LENTH;
    }
    if (cmdType & CMD_LC)        
    {
        abtTx[szTx]=cmd->lc;
        szTx+=1;
    }
    if (cmdType & CMD_DATA)
    {
        memcpy(abtTx+szTx, cmd->data,cmd->lc);
        szTx+=cmd->lc;
    }
    if (cmdType & CMD_LE)
    {
        abtTx[szTx]=cmd->le;
        szTx+=1;
    }
    if (cmdType & CMD_00)
    {
        abtTx[szTx]=0X00;
        szTx+=1;
    }
    
    // Show transmitted command
    if( debug )
    {
        printf ("Sent bits:     ");
        print_hex (abtTx, szTx);
    }

    if (nfc_initiator_transceive_bytes (pnd, abtTx, szTx, abtRx, &szRx, 0) < 0)
        return false;

    // Show received answer
    if( debug )
    {
        printf ("Received bits: ");
        print_hex (abtRx, szRx);
    } 

    if (res)
    {
        memcpy((void*)res->data,abtRx,szRx-2);
        res->size = szRx-2;
        res->sw1sw2 = abtRx[szRx-2] << 8 | abtRx[szRx-1];
    }

    if( debug )
    {
        printf ("data: ");
        print_hex (res->data, szRx-2);
        printf("SW1:%02X SW2:%02X\n", getSW1(res->sw1sw2), getSW2(res->sw1sw2));
    }
    
    return true;
}

bool
SELECT(nfc_device *pnd, bool fid,const uint8_t *data, size_t dataSize, CMD_Response *res)
{
    cmd.cla = 0x00;
    cmd.ins = 0xA4;
    cmd.p2  = 0x00;
    cmd.lc  = dataSize;
    cmd.data= data;
    cmd.le  = 0x00;

    
    if (fid)
    {
        cmd.p1 = 0x00;
    }
    else
    {
        cmd.p1 = 0x04;
    }
        
    return transmit_bytes(pnd, CMD4, &cmd, res);
}

bool
READ_BINARY(nfc_device *pnd, uint8_t fid,uint16_t offset,CMD_Response *res, size_t resSize)
{
    cmd.cla = 0x00;
    cmd.ins = 0xB0;
    cmd.le = resSize;

    //若 P1 的高三位为 100,则低 5 位为短的file 标识符,P2 为read 的偏移量。      
    if (fid)
    {
        cmd.p1=(0x80 | (fid & 0x1F));
        cmd.p2=offset & 0xFF;
    }
    else
    {
        cmd.p1=(offset >> 8) & 0x7F;
        cmd.p2=offset & 0xFF;
    }

    return transmit_bytes(pnd, CMD2, &cmd, res);
}

//TODO: cla=04
bool
READ_RECORD(nfc_device *pnd, bool encrypt, uint8_t fid,uint8_t recNo,CMD_Response *res, size_t resSize)
{
    cmd.cla = encrypt?0x04:0x00;
    cmd.ins = 0xB2;
    cmd.p1  = recNo;
    cmd.p2  = (fid & 0x1F) << 3 | ( (fid & 0x80)?0x00:0x04 );
    if (encrypt)
    {
//        cmd.lc  =
//        cmd.data= 
    }
    cmd.le = resSize;
    
    return transmit_bytes(pnd, CMD2, &cmd, res);
}

bool
GET_BALANCE(nfc_device *pnd, bool wallet,uint32_t *balance,CMD_Response *res)
{
    cmd.cla = 0x80;
    cmd.ins = 0x5C;
    cmd.p1  = 0x00;
    cmd.p2  = wallet?0x02:0x01;
    cmd.le  = 0x04;
    
    if (transmit_bytes(pnd, CMD2, &cmd, res))
        *balance = res->data[0]<<24 | res->data[1]<<16 | res->data[2]<<8 | res->data[3];
    else
        return false;

    return true;
}




/*
VERIFY_
EXTERNAL_AUTHENTICATE_
GET_CHALLENGE_
INTERNAL_AUTHENTICATE_
SELECT_
READ_BINARY_
READ_RECORD_
GET_RESPONSE_
UPDATE_BINARY_
UPDATE_RECORD_
CARD_BLOCK_
APPLICATION_UNBLOCK_
APPLICATION_BLOCK_
PIN_UNBLOCK_
UNBLOCK_
INITIALIZE_
CREDIT_FOR_LOAD_
DEBIT_FOR_
PURCHASE/CASE_
WITHDRAW/UNLOAD_
UPDATE_OVERDRAW_LIMIT_
GET_TRANSCATION_
PROVE_
GET_BALANCE_
RELOAD/CHANGE_PIN_
ERASE_DF_
PULL_
CHARGE_
WRITE_KEY_
CREATE_

WRITE_EEPROM_
READ_EEPROM_
INITIAL_EEPROM_
READ_ROM_
CALCULATE_ROM_CRC_
*/
